#ifndef _PROCESSOR_HPP_20120612
#define _PROCESSOR_HPP_20120612

#include "base.hpp"

#include "confsvr_cmd.hpp"
#include "db_cmd.hpp"
#include "balance_cmd.hpp"
#include "gateway_cmd.hpp"
#include "scence_cmd.hpp"

#include "abstract_processor.hpp"

#include "connection.hpp"
#include "cmd_comm.hpp"

using namespace cmd;
using namespace mina;

template <typename _T>
class Processor : public AbstractProcessor
{
	public :
		typedef __gnu_cxx::hash_map<uint64_t, Connection *> ConnMap;
		typedef ConnMap::iterator ConnMap_Iter;

	public :
		virtual void accept_connect(Connection & conn); 

		virtual void remove_connect(Connection & conn); 

		virtual void process_message(Connection & conn, void * data);

		/// just for one connection 
		int send_data(void * data);

		int send_data_2_all(void * data);

	public :
		ConnMap _conn_map;

		DECL_LOGGER(logger);
};

template <typename _T>
log4cplus::Logger Processor<_T>::logger = log4cplus::Logger::getInstance("Processor");

template <typename _T>
void Processor<_T>::accept_connect(Connection & conn) 
{
	LOG4CPLUS_WARN(logger, "connected. ip: " << conn.net_addr().dot_addr()
			<< ", cid: " << conn.conn_id()._cid);
	assert(_conn_map.insert(std::make_pair(conn.conn_id()._cid, &conn)).second);
}

template <typename _T>
void Processor<_T>::remove_connect(Connection & conn) 
{
	LOG4CPLUS_WARN(logger, "disconnected. ip: " << conn.net_addr().dot_addr()
			<< ", cid: " << conn.conn_id()._cid);
	_conn_map.erase(conn.conn_id()._cid);
}

template <typename _T>
int Processor<_T>::send_data(void * data)
{
	size_t sz = _conn_map.size();
	if (sz <= 0 || sz > 1)
	{
		LOG4CPLUS_ERROR(logger, "connect map size is: " << sz
				<< ", this function just use for one connection.");
		return -1;
	}

	const Connection & conn = *_conn_map.begin()->second;
	int ret = _T::instance().reactor()->send_data(conn.conn_id(), data);

	return ret;
}

template <typename _T>
int Processor<_T>::send_data_2_all(void * data)
{
	if (_conn_map.empty())
	{
		LOG4CPLUS_ERROR(logger, "not connection.");
		return -1;
	}

	ConnMap_Iter iter = _conn_map.begin();
	for (; iter != _conn_map.end(); ++ iter)
	{
		const Connection & conn = *iter->second;
		_T::instance().reactor()->send_data(conn.conn_id(), data);
	}

	return _conn_map.size();
}

template <typename _T>
void Processor<_T>::process_message(Connection & conn, void * data)
{
	CmdHead * cmd = (CmdHead*)data;

	uint32_t type = cmd->cmd_type();

#define USE_SWITCH

#define CMD_DISPATCH(class, cmd_0, cmd_1) \
	case MakeUint32_t<(uint16_t)cmd_0, (uint16_t)cmd_1>::value: \
		{ \
			class * pCmd = (class*)data; \
			LOG4CPLUS_DEBUG(logger, "datagram: " << pCmd->to_string()); \
			_T::instance().handle(conn, *pCmd); \
		}\
		break;

#include "cmd.def"

#undef CMD_DISPATCH
#undef USE_SWITCH
}

#endif

